/** @namespace GREUtils-1.0 */

(function(){
/**
 * GREUtils - is simple and easy use APIs libraries for GRE (Gecko Runtime Environment).
 *
 * Copyright (c) 2007 Rack Lin (racklin@gmail.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Date: 2007-09-16 23:42:06 -0400 (Sun, 16 Sep 2007) $
 * $Rev: 1 $
 */

GREUtils = window.GREUtils = {version: "1.0.0"};

/**
 * Object Extend function
 * Extend one object with one or more others, returning the original, modified, object.
 *
 * @method
 * @id Core.extend
 * @alias GREUtils.extend
 * @param {Object} target
 * @param {Object} source
 * @param {Object} extras
 * @return {Object}
 */
GREUtils.extend = function () {
    	// copy reference to target object
    	var target = arguments[0] || {};
        var source = arguments[1] || {};
        var extras = arguments[2] || {};

        // Extend the base object
        for ( var i in source ) {
            // Prevent never-ending loop
            if ( target == source[i] )
                continue;

            // Don't bring in undefined values
            if ( source[i] != undefined )
                target[i] = source[i];
        }

        // Extend the extra object
        for ( var i in extras ) {
            // Prevent never-ending loop
            if ( target == extras[i] )
                continue;

            // Don't bring in undefined values
            if ( extras[i] != undefined )
                target[i] = extras[i];
        }

    	// Return the modified object
    	return target;
};

/*
 * XPCOM Utilities
 */
GREUtils.XPCOM = {};
try {
    // try assign Components.classes for privilege check // shortcut by exception :D
    var _CC = Components.classes;
    GREUtils.XPCOM._EnablePrivilege = true;
}catch(ex) {
    // need Privilege and any XPCOM Operation need enablePrivilege.
    // netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
    GREUtils.XPCOM._EnablePrivilege = false;
}
GREUtils.extend(GREUtils.XPCOM, {

    /**
     * Return class from Components.classes by ClassName.
     *
     * return null if ClassName not exists.
     *
     * @method
     * @id XPCOM.Cc
     * @alias GREUtils.XPCOM.Cc
     * @param {String} className
     * @return {Object}
     */
    Cc: function (cName) {
        try {
            if(cName in Components.classes) return Components.classes[cName];
            return null;
        }catch(ex) {
            // netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
            return null;
        }
    },

    /**
     * Return interface from Components.interfaces by Interface Name.
     *
     * return null if Interface Name not exists.
     *
     * @method
     * @id XPCOM.Ci
     * @alias GREUtils.XPCOM.Ci
     * @param {String} interfaceName
     * @return {Object}
     */
    Ci: function (ifaceName){
        try {
            if( ifaceName in Components.interfaces) return Components.interfaces[ifaceName];
            return null;
        }catch(ex) {
            // netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
            return null;
        }
    },

    /**
     * Return Components.results or [].
     *
     * @method
     * @id XPCOM.Cr
     * @alias GREUtils.XPCOM.Cr
     * @return {Array}
     */
    Cr: function (){
        try {
            return Components.results;
        }catch(ex) {
            // netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
            return [];
        }
    },

    /**
     * Return Class Instance by getService.
     *
     * return null if ClassName or Interface not exists.
     *
     * @method
     * @id XPCOM.getService
     * @alias GREUtils.XPCOM.getService
     * @param {String} className
     * @param {String} interfaceName
     * @return {Object}
     */
    getService: function (cName, ifaceName) {
        var cls = this.Cc(cName);
        var iface = this.Ci(ifaceName);
        if (cls && iface) return cls.getService(iface);
        else return null;
    },

    /**
     * Return Class Instance by createInstance.
     *
     * return null if ClassName or Interface not exists.
     *
     * @method
     * @id XPCOM.createInstance
     * @alias GREUtils.XPCOM.createInstance
     * @param {String} className
     * @param {String} interfaceName
     * @return {Object}
     */
    createInstance: function (cName, ifaceName) {
        var cls = this.Cc(cName);
        var iface = this.Ci(ifaceName);
        if (cls && iface) return cls.createInstance(iface);
        else return null;
    },

    /**
     * Query Class Interface.
     *
     * @method
     * @id XPCOM.queryInterface
     * @alias GREUtils.XPCOM.queryInterface
     * @param {String} className
     * @param {String} interfaceName
     * @return {Object}
     */
    queryInterface: function (obj, ifaceName) {
        if (typeof(obj) == "object") {
            var iface = this.Ci(ifaceName);
            if (iface) return obj.QueryInterface(iface);
        }
        return obj;
    }

});


/*
 * Useful Functions
 */
GREUtils.extend(GREUtils, {
    _data: {},

    /**
     * Get Application Infomation.
     *
     * see nsIXULAppInfo Interface.
     *
     * @method
     * @id Core.getAppInfo
     * @alias GREUtils.getAppInfo
     * @return {Object}
     */
    getAppInfo: function () {
        return GREUtils.XPCOM.getService("@mozilla.org/xre/app-info;1", "nsIXULAppInfo");
    },

    /**
     * Get Runtime Infomation.
     *
     * see nsIXULRuntime Interface.
     *
     * @method
     * @id Core.getRuntimeInfo
     * @alias GREUtils.getRuntimeInfo
     * @return {Object}
     */
    getRuntimeInfo: function() {
        return GREUtils.XPCOM.getService("@mozilla.org/xre/app-info;1", "nsIXULRuntime");
    },


    /**
     * Synchronously loads and executes the script from the specified URL.
     *
     * default scope is window.
     *
     * @method
     * @id Core.include
     * @alias GREUtils.include
     * @param {Object} scriptSrc
     * @param {Object} scope
     */
    include: function (scriptSrc, scope) {

        var objScope = scope || window;

        if (scriptSrc.indexOf('://') == -1) {
            scriptSrc = document.location.href.substring(0, document.location.href.lastIndexOf('/') +1) + scriptSrc;
        }

        var rv;
        try {
            if(!GREUtils.XPCOM._EnablePrivilege) netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
            GREUtils.XPCOM.getService("@mozilla.org/moz/jssubscript-loader;1", "mozIJSSubScriptLoader").loadSubScript(scriptSrc, objScope);
            rv = GREUtils.XPCOM.Cr().NS_OK;
        } catch (e) {
            rv = - GREUtils.XPCOM.Cr().NS_ERROR_INVALID_ARG;
        }
        return rv;
    },

    /**
     * Synchronously loads and executes the script from the specified URL.
     *
     * Specified URL will loads and executes once.
     *
     * default scope is window.
     *
     * @method
     * @id Core.include_once
     * @alias GREUtils.include_once
     * @param {Object} scriptSrc
     * @param {Object} scope
     */
    include_once: function(scriptSrc, scope) {

        var scriptJS = scriptSrc.substring( scriptSrc.lastIndexOf('/') + 1, scriptSrc.length );
        var scriptJS_loaded = encodeURIComponent(scriptJS)+"_LOADED";
        if(scriptJS_loaded in this._data) {
            return GREUtils.XPCOM.Cr().NS_OK;
        } else {
            rv = this.include(scriptSrc, scope);
            if(rv == GREUtils.XPCOM.Cr().NS_OK) {
                this._data[scriptJS_loaded] = rv;
            }
            return rv;
        }
    },

    /**
     * Convert XUL String to DOM Elements.
     *
     * XUL String namespace is http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul
     * You can specified your custom namespace.
     *
     * @method
     * @id Core.domXULString
     * @alias GREUtils.domXULString
     * @param {String} xulString
     * @param {String} xmlns
     * @return {Object}
     */
    domXULString: function (xulString, xmlns) {

        xmlns = xmlns || "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
        // try with box container and namespace for easy use.
        var xulString2 = '<box xmlns="'+xmlns+'">'+xulString+'</box>';

        var parser=new DOMParser();
        var resultDoc=parser.parseFromString(xulString2,"text/xml");
        if (resultDoc.documentElement.tagName == "parsererror") return xulString
        else {
            if(resultDoc.documentElement.childNodes.length == 1) return resultDoc.documentElement.firstChild;
            else return resultDoc.documentElement;
        }

    },

    /**
     * Convert HTML String to DOM Elements.
     *
     * HTML String namespace is http://www.w3.org/1999/xhtml
     * You can specified your custom namespace.
     *
     * @method
     * @id Core.domHTMLString
     * @alias GREUtils.domHTMLString
     * @param {String} htmlString
     * @param {String} xmlns
     * @return {Object}
     */
    domHTMLString: function (htmlString, xmlns) {

        xmlns = xmlns || "http://www.w3.org/1999/xhtml";
        // try with div container and namespace for easy use.
        var htmlString2 = '<div xmlns="'+xmlns+'">'+htmlString+'</div>';

        var parser=new DOMParser();
        var resultDoc=parser.parseFromString(htmlString2,"text/xml");
        if (resultDoc.documentElement.tagName == "parsererror") return htmlString
        else {
            if(resultDoc.documentElement.childNodes.length == 1) return resultDoc.documentElement.firstChild;
            else return resultDoc.documentElement;
        }

    },

    /**
     * Quit Application
     *
     * see nsIAppStartup
     *
     * @method
     * @id Core.quitApplication
     * @alias GREUtils.quitApplication
     * @param {Number} mode
     */
    quitApplication: function() {
        var mode = arguments[0] || 2;
        GREUtils.XPCOM.getService('@mozilla.org/toolkit/app-startup;1','nsIAppStartup').quit(mode);
    },

    /**
     * Restart Application
     *
     * see nsIAppStartup
     *
     * @method
     * @id Core.restartApplication
     * @alias GREUtils.restartApplication
     */
    restartApplication: function() {
        this.quitApplication((16|2));
    },

    /**
     * Ram Back  notifyObservers memory-pressure
     *
     * see memory-pressure
     *
     * @method
     * @id Core.ramback
     * @alias GREUtils.ramback
     */
    ramback: function() {
        var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);

        // since we don't know the order of how things are going to go, fire these multiple times
        observerService.notifyObservers(null, "memory-pressure", "heap-minimize");
        observerService.notifyObservers(null, "memory-pressure", "heap-minimize");
        observerService.notifyObservers(null, "memory-pressure", "heap-minimize");

    }

});

/*
 * XPCOM Charset Convert
 * Unicode converter
 */
GREUtils.Charset = GREUtils.extend({}, {

    /**
     * Convert text from charset to Unicode String
     *
     * @method
     * @id Charset.convertToUnicode
     * @alias GREUtils.Charset.convertToUnicode
     * @param {String} text
     * @param {String} charset
     * @return {String}
     */
    convertToUnicode: function(text, charset) {
        try {
            var conv = GREUtils.XPCOM.getService("@mozilla.org/intl/scriptableunicodeconverter", "nsIScriptableUnicodeConverter");
            conv.charset = charset ? charset : "UTF-8";
            return conv.ConvertToUnicode(text);
        }catch (ex) {
            return text;
        }
    },

    /**
     * Convert Unicode String to specified charset.
     *
     * @method
     * @id Charset.convertFromUnicode
     * @alias GREUtils.Charset.convertFromUnicode
     * @param {String} text
     * @param {String} charset
     * @return {String}
     */
    convertFromUnicode: function(text, charset) {
        try {
            var conv = GREUtils.XPCOM.getService("@mozilla.org/intl/scriptableunicodeconverter", "nsIScriptableUnicodeConverter");
            conv.charset = charset ? charset : "UTF-8";
            return conv.ConvertFromUnicode(text);
        }catch (ex) {
            return text;
        }
    },

    /**
     * Convert Charset
     *
     * @method
     * @id Charset.convertCharset
     * @alias GREUtils.Charset.convertCharset
     * @param {String} text
     * @param {String} in_charset
     * @param {String} out_charset
     * @return {String}
     */
    convertCharset: function (text, in_charset, out_charset) {
        return this.convertFromUnicode(this.convertToUnicode(text, in_charset), out_charset);
    }
});


/*
 *  XPCOM Preferences Services
 */
GREUtils.Pref = GREUtils.extend({}, {

    /**
     * Get Application Preferences Service.
     *
     * see nsIPrefBranch2
     *
     * @method
     * @id Pref.getPrefService
     * @alias GREUtils.Pref.getPrefService
     * @return {Object}
     */
    getPrefService: function () {
        return GREUtils.XPCOM.getService("@mozilla.org/preferences-service;1", "nsIPrefBranch2");
    },

    /**
     * Get Preference Value By Key.
     *
     * Auto Detect preference types.
     *
     * @method
     * @id Pref.getPref
     * @alias GREUtils.Pref.getPref
     * @param {String} prefName
     * @param {Object} PrefService
     * @return {Object}
     */
    getPref: function() {
        var prefName = arguments[0] ;
        var prefs = (arguments[1]) ? arguments[1] : this.getPrefService();
        var nsIPrefBranch = GREUtils.XPCOM.Ci("nsIPrefBranch");
        var type = prefs.getPrefType(prefName);
        if (type == nsIPrefBranch.PREF_STRING)
            return prefs.getCharPref(prefName);
        else if (type == nsIPrefBranch.PREF_INT)
            return prefs.getIntPref(prefName);
        else if (type == nsIPrefBranch.PREF_BOOL)
            return prefs.getBoolPref(prefName);
    },

    /**
     * Set Preference Value By Key.
     *
     * Auto Detect preference types.
     *
     * @method
     * @id Pref.setPref
     * @alias GREUtils.Pref.setPref
     * @param {String} prefName
     * @param {Object} value
     * @param {Object} PrefService
     */
    setPref: function() {
        var prefName = arguments[0] ;
        var value = arguments[1];
        var prefs = (arguments[2]) ? arguments[2] : this.getPrefService();
        var nsIPrefBranch = GREUtils.XPCOM.Ci("nsIPrefBranch");
        var type = prefs.getPrefType(prefName);
        if (type == nsIPrefBranch.PREF_STRING)
            prefs.setCharPref(prefName, value);
        else if (type == nsIPrefBranch.PREF_INT)
            prefs.setIntPref(prefName, value);
        else if (type == nsIPrefBranch.PREF_BOOL)
            prefs.setBoolPref(prefName, value);
    }

});

/*
 *  XPCOM File System Services
 */
GREUtils.File = GREUtils.extend({}, {

    /**
     * Get File or Path ILocalFile Interface
     *
     * @method
     * @id File.getFile
     * @alias GREUtils.File.getFile
     * @param {String} sFile
     * @return {Object}
     */
    getFile: function(sFile) {
        var autoCreate = arguments[1] || false;
        if (/^file:/.test(sFile)) sFile = sFile.replace("file://", "");
        var obj = GREUtils.XPCOM.createInstance('@mozilla.org/file/local;1', 'nsILocalFile');
        obj.initWithPath(sFile);
        if(obj.exists()) return obj;
        else if(autoCreate) {
            try {
                obj.create(0x00, 0664);
                return obj;
            }catch(ex) {
                return null;
            }
        }else {
            return null;
        }
    },

    /**
     * Get URL nsIURL Interface.
     *
     * @method
     * @id File.getURL
     * @alias GREUtils.File.getURL
     * @param {Object} sURL
     */
    getURL: function(sURL) {
        var mURL = null;
        if (!/^file:/.test(sURL)) {
            mURL = GREUtils.XPCOM.createInstance("@mozilla.org/network/standard-url;1", "nsIURL");
        } else {
            mURL = GREUtils.XPCOM.getService("@mozilla.org/network/io-service;1", "nsIIOService").newURI(sURL, "UTF-8", null);
            mURL = GREUtils.XPCOM.queryInterface(mURL, "nsIFileURL");
        }
        mURL.spec = sURL;
        return mURL;
    },

    /**
     * Get File OutputStream
     *
     * @method
     * @id File.getURL
     * @alias GREUtils.File.getURL
     * @param {Object} file
     * @param {String} mode
     * @param {Number} perm
     */
    getOutputStream: function(file, mode, perm) {
        var nsIFile = (typeof(file)=="string") ? this.getFile(file) : file;

        var NS_MODE = (0x20 | 0x02);
        if(typeof(mode)=="string" && mode.indexOf("w") != -1) NS_MODE = (0x20 | 0x02);
        if(typeof(mode)=="string" && mode.indexOf("a") != -1) NS_MODE = (0x04 | 0x10);

        var NS_PERM = perm || 0644;

        if (nsIFile == null) {
            var nsIFile = GREUtils.XPCOM.createInstance('@mozilla.org/file/local;1', 'nsILocalFile');
            nsIFile.initWithPath(file);
            nsIFile.create(0x00, NS_PERM);
        }

        var fs = GREUtils.XPCOM.createInstance("@mozilla.org/network/file-output-stream;1", "nsIFileOutputStream");

        fs.init(nsIFile, NS_MODE, NS_PERM, null);

        if(typeof(mode)=="string" && mode.indexOf("b") != -1) {
            var binstream = GREUtils.XPCOM.createInstance("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream");
            binstream.setOutputStream(fs);
            return binstream;
        }else return fs;

    },

    /**
     * Get File InputStream
     *
     * @method
     * @id File.getInputStream
     * @alias GREUtils.File.getInputStream
     * @param {Object} file
     * @param {String} mode
     * @param {Number} perm
     */
    getInputStream: function(file, mode, perm) {
        var nsIFile = (typeof(file)=="string") ? this.getFile(file) : file;

        if(nsIFile == null) return null;

        var NS_MODE = 0x01; // RDONLY prio.h
        if(typeof(mode)=="string" && mode.indexOf("r") != -1) NS_MODE = 0x01;

        var NS_PERM = perm || 0644;

        var fs = GREUtils.XPCOM.createInstance("@mozilla.org/network/file-input-stream;1", "nsIFileInputStream");

        fs.init(nsIFile, NS_MODE, NS_PERM, null);

        if(typeof(mode)=="string" && mode.indexOf("b") != -1) {
            var binstream = GREUtils.XPCOM.createInstance("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
            binstream.setInputStream(fs);
            return binstream;
        }else {
            var scriptstream = GREUtils.XPCOM.createInstance("@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream");
            scriptstream.init(fs);
            return scriptstream;
        }
    },

    /**
     * Get File LineInputStream
     *
     * see nsILineInputStream
     *
     * @method
     * @id File.getLineInputStream
     * @alias GREUtils.File.getLineInputStream
     * @param {Object} file
     * @return {Object}
     */
    getLineInputStream: function(file) {
        var nsIFile = (typeof(file)=="string") ? this.getFile(file) : file;
        if(nsIFile == null) return null;

        var fs = GREUtils.XPCOM.createInstance("@mozilla.org/network/file-input-stream;1", "nsIFileInputStream");
        fs.init(nsIFile, 0x01, 0644, null);
        return GREUtils.XPCOM.queryInterface(fs, "nsILineInputStream");
    },

    /**
     * Read File Contents to Array
     *
     * @method
     * @id File.readAllLine
     * @alias GREUtils.File.readAllLine
     * @param {Object} file
     * @return {Array}
     */
    readAllLine: function (file) {
        var lineStream = this.getLineInputStream(file);
        var lines = [];
        var buf = {value:""};

        if(!lineStream) return lines;

        do  {
            var rv = lineStream.readLine(buf);
            lines.push(buf.value);
        }while(rv);

        lineStream.close();
        return lines;
    },

    /**
     * Read File Contents to Binary String.
     *
     * @method
     * @id File.readAllBytes
     * @alias GREUtils.File.readAllBytes
     * @param {Object} file
     * @return {String}
     */
	readAllBytes: function(file) {
        var nsIFile = (typeof(file)=="string") ? this.getFile(file) : file;
		var size = nsIFile.fileSize;
        var binStream = this.getInputStream(nsIFile, "rb", 0644);
		var binaryString = binStream.readBytes(size);
		binStream.close();
		return binaryString;

	},


    /**
     * Write Array Contents to File
     *
     * @method
     * @id File.writeAllLine
     * @alias GREUtils.File.writeAllLine
     * @param {Object} file
     * @return {Array}
     */
    writeAllLine: function (file) {
        var lineStream = this.getLineInputStream(file);
        var lines = [];
        var buf = {value:""};

        if(!lineStream) return lines;

        do  {
            var rv = lineStream.readLine(buf);
            lines.push(buf.value);
        }while(rv);

        lineStream.close();
        return lines;
    },

    /**
     * Write Binary String Contents to File
     *
     * @method
     * @id File.writeAllBytes
     * @alias GREUtils.File.writeAllBytes
     * @param {Object} file
     * @return {String}
     */
	writeAllBytes: function(file) {
        var nsIFile = (typeof(file)=="string") ? this.getFile(file) : file;
		var size = nsIFile.fileSize;
        var binStream = this.getInputStream(nsIFile, "rb", 0644);
		var binaryString = binStream.readBytes(size);
		binStream.close();
		return binaryString;

	},



    /**
     * Executes the file
     *
     * blocking: Whether to wait until the process terminates before returning or not
     *
     * @method
     * @id File.run
     * @alias GREUtils.File.run
     * @param {Object} nsFile
     * @param {Object} aArgs
     * @return {Number}
     */
    run: function (nsFile, aArgs) {
        var nsIFile = (typeof(nsFile)=="string") ? this.getFile(nsFile) : nsFile;
        if(nsIFile == null) return -1;
        if(nsIFile.isDirectory()) return -2;

        var blocking = arguments[2] | false;

        try {
            var process = GREUtils.XPCOM.createInstance("@mozilla.org/process/util;1", "nsIProcess");
            // var process = GREUtils.XPCOM.getService("@mozilla.org/process/util;1", "nsIProcess");

            process.init(nsIFile);

            var len = 0;
            if (aArgs) len = aArgs.length;
            else aArgs = null;
            rv = process.run(blocking, aArgs, len);
       } catch (e) { rv = -3 }
       return rv;
    },

    /**
     * Convert chrome:// URL to LocalFile spec.
     *
     * return  nsIURI Interface
     *
     * @method
     * @id File.chromeToPath
     * @alias GREUtils.File.chromeToPath
     * @param {String} chromePath
     * @return {Object}
     */
    chromeToPath: function(chromePath) {
        var uri = this.getURL(chromePath);
        var cr = GREUtils.XPCOM.getService("@mozilla.org/chrome/chrome-registry;1", "nsIChromeRegistry");
        rv = cr.convertChromeURL(uri);
        return rv;
    }

});

/*
 *  Dialog Services
 */
GREUtils.Dialog = GREUtils.extend({}, {

    /**
     * Open Dialog
     *
     * @method
     * @id Dialog.openDialog
     * @alias GREUtils.Dialog.openDialog
     * @param {String} sURL
     * @param {Number} posX
     * @param {Number} posY
     * @param {Number} width
     * @param {Number} height
     */
    openDialog: function(sURL, posX, posY, width, height) {

      var args = "chrome,dialog,dependent=yes,resize=yes";
      if(posX) args += ",screenX="+posX;
      if(posY) args += ",screenY="+posY;
      if(width) args += ",width="+width;
      if(height) args += ",height="+height;

      return window.openDialog(sURL, "_blank", args, arguments[5]);
    },

    /**
     * Open Modal Dialog
     *
     * @method
     * @id Dialog.openModalDialog
     * @alias GREUtils.Dialog.openModalDialog
     * @param {String} sURL
     * @param {Number} posX
     * @param {Number} posY
     * @param {Number} width
     * @param {Number} height
     */
    openModalDialog: function(sURL, posX, posY, width, height) {

      var args = "chrome,dialog,dependent=no,modal,resize=yes";
      if(posX) args += ",screenX="+posX;
      if(posY) args += ",screenY="+posY;
      if(width) args += ",width="+width;
      if(height) args += ",height="+height;

      return window.openDialog(sURL, "_blank", args, arguments[5]);
    },

    /**
     * Open Full Screen Window
     *
     * @method
     * @id Dialog.openFullScreen
     * @alias GREUtils.Dialog.openFullScreen
     * @param {String} sURL
     */
    openFullScreen : function (sURL) {
      var sName = arguments[1] || '_blank';
      var sArgs = arguments[2] || false ;
      var args = "chrome,dialog=no,resize=no";
      args += ",x=0,y=0";
      args += ",screenX="+0;
      args += ",screenY="+0;
      args += ",width="+window.screen.width;
      args += ",height="+window.screen.height;
      if(sArgs) args += "," + sArgs;

      return window.openDialog(sURL, sName, args, arguments[3]);
    },

    /**
     * Open Splash Window
     *
     * @method
     * @id Dialog.openSplash
     * @alias GREUtils.Dialog.openSplash
     * @param {String} sURL
     * @param {Number} posX
     * @param {Number} posY
     * @param {Number} width
     * @param {Number} height
     */
    openSplash : function (sURL, posX, posY, width, height) {

        if (/Mac/g.test(window.navigator.platform)) popup="";

        var args = "chrome,dialog=no,titlebar=no";
        if (!(/Mac/g.test(window.navigator.platform))) args+=",popup";
        if(posX) args += ",screenX="+posX;
        if(posY) args += ",screenY="+posY;
        if(width) args += ",width="+width;
        if(height) args += ",height="+height;

        return window.openDialog(sURL, "_blank", args);
    },

    /**
     * Get File Picker
     *
     * see nsIFilePicker
     *
     * @method
     * @id Dialog.getFilePicker
     * @alias GREUtils.Dialog.getFilePicker
     * @return {Object}
     */
    getFilePicker: function() {
        return GREUtils.XPCOM.getService("@mozilla.org/filepicker;1", "nsIFilePicker");
    },

    /**
     * Open File Picker Dialog
     *
     * @method
     * @id Dialog.openFilePicker
     * @alias GREUtils.Dialog.openFilePicker
     * @param {String} sDir
     * @return {String}
     */
    openFilePicker: function(sDir){
        var filePicker = this.getFilePicker();
        if(sDir) {
            if (typeof(sDir)=="object" && GREUtils.XPCOM.queryInterface(sDir, "nsIFile")) {
              filePicker.displayDirectory = sDir;
            }
            if (typeof(sDir)=="string") {
                filePicker.displayDirectory = GREUtils.File.getFile(sDir);
            }
        }
        filePicker.show();
        return (filePicker.file.path.length > 0 ? filePicker.file.path : null);
    },

    /**
     * Alert Dialog
     *
     * @method
     * @id Dialog.alert
     * @alias GREUtils.Dialog.alert
     * @param {String} dialogTitle
     * @param {String} dialogText
     */
    alert: function(dialogTitle, dialogText) {
        // get a reference to the prompt service component.
        var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                    .getService(Components.interfaces.nsIPromptService);
        promptService.alert(window, dialogTitle, dialogText);
    },

    /**
     * Confirm Dialog
     *
     * @method
     * @id Dialog.confirm
     * @alias GREUtils.Dialog.confirm
     * @param {String} dialogTitle
     * @param {String} dialogText
     * @return {Boolean}
     */
    confirm: function(dialogTitle, dialogText) {
        // get a reference to the prompt service component.
        var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                    .getService(Components.interfaces.nsIPromptService);
        return promptService.confirm(window, dialogTitle, dialogText);
    }

});


/*
 *  Sound Services
 */
GREUtils.Sound = GREUtils.extend({}, {

    /**
     * Get Sound Service
     * see  nsISound Interface document.
     *
     * @method
     * @id Sound.getSoundService
     * @alias GREUtils.Sound.getSoundService
     * @return {Object}
     *
     */
    getSoundService: function() {
        return GREUtils.XPCOM.getService("@mozilla.org/sound;1", "nsISound");
    },

    /**
     * Play Sound by specified URL
     *
     * @method
     * @id Sound.play
     * @alias GREUtils.Sound.play
     * @param {String} sURL
     */
    play: function(sURL) {
        mURL = GREUtils.File.getURL(sURL);
        var snd = this.getSoundService();
        snd.init();
        return snd.play(mURL);
    },

    /**
     * Play Sound Beep
     *
     * @method
     * @id Sound.beep
     * @alias GREUtils.Sound.beep
     */
    beep: function() {
        return this.getSoundService().beep();
    },

    /**
     * Play System Sound by specified URL
     *
     * @method
     * @id Sound.playSystemSound
     * @alias GREUtils.Sound.playSystemSound
     * @param {String} sURL
     */
    playSystemSound: function(sURL) {
        mURL = GREUtils.File.getURL(sURL);
        var snd = this.getSoundService();
        snd.init();
        return snd.playSystemSound(mURL);
    }
});

/**
 * Controller and CommandDispatcher Helper
 */
GREUtils.ControllerHelper = GREUtils.extend({}, {

    /**
     * Append Controller to Window Controllers.
     * Then call Controller's init method
     *
     * @method
     * @id ControllerHelper.appendController
     * @alias GREUtils.ControllerHelper.appendController
     * @param {Object} controller
     */
    appendController: function(controller) {
        if(controller) window.controllers.appendController(controller);
        var app = arguments[1] || window;

        if(typeof(controller.init) == 'function') {
            controller.init(app);
        }
    },

    /**
     * Call CommandDispatcher to run Command By CommandName
     *
     * @method
     * @id ControllerHelper.doCommand
     * @alias GREUtils.ControllerHelper.doCommand
     * @param {String} sCmd
     */
    doCommand : function(sCmd) {
        var cmdDispatcher = document.commandDispatcher || top.document.commandDispatcher || window.controllers;
        var controller = cmdDispatcher.getControllerForCommand(sCmd);

        if(controller) return controller.doCommand(sCmd);

        // try window controller
        controller = window.controllers.getControllerForCommand(sCmd);
        if (controller) return controller.doCommand(sCmd);
    }

});

/**
 * ControllerAdapter
 *
 * @classDescription ControllerAdapter
 * @id ControllerAdapter
 * @alias GREUtils.ControllerAdapter
 */
GREUtils.ControllerAdapter = GREUtils.extend({}, {
    _app: null,
    _privateCommands: {'_privateCommands':1, '_app':1, 'init':1, 'supportsCommand':1, 'isCommandEnabled':1, 'doCommand':1, 'onEvent':1},

    /**
     * Controller Default Init method
     *
     * Normally don't need to override it.
     *
     * @method
     * @id ControllerHelper.init
     * @alias GREUtils.ControllerHelper.init
     * @param {Object} aApp
     */
    init : function(aApp) {
        this._app = aApp;
    },

    /**
     * Controller Support Command
     *
     * Normally not need to override it.
     *
     * @method
     * @id ControllerHelper.supportsCommand
     * @alias GREUtils.ControllerHelper.supportsCommand
     * @param {String} sCmd
     */
    supportsCommand: function(sCmd) {
        if( (!(sCmd in this._privateCommands)) && (sCmd in this) && typeof(this[sCmd]) == 'function' ) {
            return true;
        }
        return false;
    },

    /**
     * Controller isCommandEnabled
     *
     * @method
     * @id ControllerHelper.isCommandEnabled
     * @alias GREUtils.ControllerHelper.isCommandEnabled
     * @param {String} sCmd
     * @return {Boolean}
     */
    isCommandEnabled: function(sCmd) {
        return true;
    },

    /**
     * Controller doCommand
     *
     * Normally not need to override it.
     *
     * @method
     * @id ControllerHelper.doCommand
     * @alias GREUtils.ControllerHelper.doCommand
     * @param {String} sCmd
     */
    doCommand : function(sCmd) {
        if( (!(sCmd in this._privateCommands)) && (sCmd in this) && typeof(this[sCmd]) == 'function') {
            if(this.isCommandEnabled(sCmd)) return this[sCmd].call(this, arguments);
        }
    },

    /**
     * Controller onEvent
     *
     * Normally not need to override it.
     *
     * @method
     * @id ControllerHelper.onEvent
     * @alias GREUtils.ControllerHelper.onEvent
     * @param {String} sCmd
     */
    onEvent: function(sCmd) {
        if((sCmd in this) && typeof(this[sCmd]) == 'function') {
            if(this.isCommandEnabled(sCmd)) return this[sCmd].call(this, arguments);
        }
    }

});

})();
